package com.xudu.zerocodebackend.manager;

import com.qcloud.cos.utils.Jackson;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.sts.v20180813.StsClient;
import com.tencentcloudapi.sts.v20180813.models.GetFederationTokenRequest;
import com.tencentcloudapi.sts.v20180813.models.GetFederationTokenResponse;
import com.xudu.zerocodebackend.config.CosClientConfig;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @className: CosManager
 * @description: TODO
 * @author: xudu
 * @create: 2025-07-28
 */
@Slf4j
@Component
public class CosManager {

    @Resource
    private CosClientConfig cosConfig;

    // 允许的图片文件扩展名
    private static final String[] ALLOWED_IMAGE_EXTENSIONS = {
            ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"
    };

    private static final Random RANDOM = new Random();

    /**
     * 获取临时密钥和上传信息
     * @param filename 原始文件名
     * @return STS 响应信息
     * @throws Exception 异常
     */
    public Map<String, Object> getTemporaryCredentials(String filename) throws Exception {
        // 1. 验证文件名
        if (filename == null || filename.trim().isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }

        // 2. 验证文件扩展名
        if (!this.isValidExtension(filename, ALLOWED_IMAGE_EXTENSIONS)) {
            throw new IllegalArgumentException("不支持的文件类型，仅支持图片文件");
        }

        // 3. 生成 COS 文件路径
        String cosKey = this.generateCosKey(filename);

        // 4. 调用腾讯云 STS 服务获取临时密钥
        Map<String, Object> stsCredentials = this.getStsCredentials(filename);
        stsCredentials.put("url", cosConfig.getHost() + "/" + cosKey);
        stsCredentials.put("key", cosKey);
        stsCredentials.put("region", cosConfig.getRegion());
        stsCredentials.put("bucket", cosConfig.getBucket());
        return stsCredentials;

    }

    /**
     * 获取 STS 临时凭证
     * @param cosKey 文件名称
     * @return STS 响应
     * @throws Exception 异常
     */
    private Map<String, Object> getStsCredentials(String cosKey) throws Exception {
        try {
            // 创建凭证
            Credential cred = new Credential(cosConfig.getSecretId(), cosConfig.getSecretKey());

            // 创建 STS 客户端
            StsClient client = new StsClient(cred, cosConfig.getRegion());

            // 构建请求
            GetFederationTokenRequest req = new GetFederationTokenRequest();
            req.setName("frontend-user");
            req.setDurationSeconds(1800L);
            // 构建策略文档
            String policy = this.getPolicy(cosKey);
            req.setPolicy(policy);

            // 发起请求
            GetFederationTokenResponse resp = client.GetFederationToken(req);

            // 构建响应
            Map<String, Object> stsResponse = new HashMap<>();
            stsResponse.put("TmpSecretId", resp.getCredentials().getTmpSecretId());
            stsResponse.put("TmpSecretKey", resp.getCredentials().getTmpSecretKey());
            stsResponse.put("SessionToken", resp.getCredentials().getToken());
            stsResponse.put("ExpiredTime", resp.getExpiredTime());
            stsResponse.put("StartTime", System.currentTimeMillis() / 1000);
            stsResponse.put("Expiration", resp.getExpiration());

            return stsResponse;

        } catch (TencentCloudSDKException e) {
            log.error("获取临时密钥失败", e);
            throw new Exception("获取临时密钥失败: " + e.getMessage(), e);
        }
    }

    public String getPolicy(String cosKey) {
        String bucket = cosConfig.getBucket();
        String appId = cosConfig.getAppId();
        String region = cosConfig.getRegion();

        // 启用关键安全限制
        Boolean limitContentType = true;
        Boolean limitContentLength = true;

        Map<String, Object> condition = new HashMap<>();

        // 限制Content-Type
        if (limitContentType) {
            condition.put("string_like_if_exist", Map.of("cos:content-type", "image/*"));
        }

        // 限制文件大小 (5MB)
        if (limitContentLength) {
            condition.put("numeric_less_than_equal", Map.of("cos:content-length", 5L * 1024 * 1024));
        }

        // 精确资源路径 (存储桶 + 具体文件)
        String resourceForBucket = "qcs::cos:" + region + ":uid/" + appId + ':' + bucket + "/";
        //String resourceForObject = resourceForBucket + "/" + cosKey;
        //List<String> resources = Arrays.asList(resourceForBucket, resourceForObject);

        // 允许的操作列表
        List<String> allowActions = Arrays.asList(
                "name/cos:HeadBucket",
                "name/cos:PutObject",
                "name/cos:InitiateMultipartUpload",
                "name/cos:ListMultipartUploads",
                "name/cos:ListParts",
                "name/cos:UploadPart",
                "name/cos:CompleteMultipartUpload"
        );

        // 构建策略
        Map<String, Object> policy = Map.of(
                "version", "2.0",
                "statement", Collections.singletonList(Map.of(
                        "action", allowActions,
                        "effect", "allow",
                        "resource", resourceForBucket,
                        "condition", condition
                ))
        );

        return Jackson.toJsonPrettyString(policy);
    }

    /**
     * 生成 COS 文件路径
     * @param originalFilename 原始文件名
     * @return 生成的文件路径
     */
    public String generateCosKey(String originalFilename) {
        // 获取文件扩展名
        String extension = "";
        if (originalFilename != null && originalFilename.contains(".")) {
            extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        }

        // 生成日期路径
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String dateStr = sdf.format(new Date());
        // 生成随机数
        int randomNum = RANDOM.nextInt(1000000);
        String randomStr = String.format("%06d", randomNum);

        // 组合文件路径：file/20240728/20240728_123456.jpg
        return String.format("file/%s/%s_%s%s", dateStr, dateStr, randomStr, extension);
    }

    /**
     * 从文件名中提取扩展名
     * @param filename 文件名
     * @return 扩展名（包含点号）
     */
    public String getFileExtension(String filename) {
        if (filename == null || !filename.contains(".")) {
            return "";
        }
        return filename.substring(filename.lastIndexOf("."));
    }

    /**
     * 验证文件扩展名是否合法
     * @param filename 文件名
     * @param allowedExtensions 允许的扩展名数组
     * @return 是否合法
     */
    public boolean isValidExtension(String filename, String[] allowedExtensions) {
        if (filename == null || allowedExtensions == null) {
            return false;
        }

        String extension = getFileExtension(filename).toLowerCase();
        for (String allowed : allowedExtensions) {
            if (extension.equals(allowed.toLowerCase())) {
                return true;
            }
        }
        return false;
    }

}
